package ongd.servicios.persistencia;

import java.util.HashMap;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import ongd.negocio.gestion.Apadrinado;
import ongd.negocio.gestion.Configuracion;
import ongd.negocio.gestion.Cuota;
import ongd.negocio.gestion.Entidad;
import ongd.negocio.gestion.Fraccionado;
import ongd.negocio.gestion.Indice;
import ongd.negocio.gestion.Persona;
import ongd.negocio.gestion.PersonaContacto;
import ongd.negocio.gestion.Proyecto;
import ongd.negocio.gestion.Subvencion;
import ongd.negocio.gestion.Usuario;
import ongd.servicios.persistencia.exceptions.IllegalOrphanException;
import ongd.servicios.persistencia.exceptions.NonexistentEntityException;
import ongd.servicios.persistencia.exceptions.PreexistingEntityException;

/**
 * Clase que se encargará de crear los controladores que realizarán las
 * operaciones sobre la base de datos.
 *
 * @author <a href="mailto:egi0002@alu.ubu.es">Elena García Iglesias</a>
 * @author <a href="mailto:cms0021@alu.ubu.es">Cristina Martínez Sanz</a>
 * @version 1.0 20120124
 *
 */
public class ControladorPersistencia {

    /**
     * Objeto que va a contener los controladores.
     */
    private HashMap<Class, AJPAControlador> hsmJPAControladores;
    /**
     * Objeto de tipo EntityManager.
     */
    private EntityManager entity;
    /**
     * Booleano que indicará donde corresponda si es necesario iniciar o 
     * cerrar una transacción.
     */
    private boolean blnTransaccion;

    /**
     * Constructor de la clase.
     */
    public ControladorPersistencia() {
        hsmJPAControladores = new HashMap<Class, AJPAControlador>();
        blnTransaccion = false;
    }

    /**
     * Método que conecta con la base de datos.
     * @param prueba Booleano que indica si conectaremos con la base de datos
     * de pruebas o no
     * @return true si se realiza la conexión con éxito
     */
    public boolean conectarBaseDatos(boolean prueba) {
        boolean resultado = true;
        try {
            if (!prueba) {
                entity = Persistence.createEntityManagerFactory("ONGD_Persona_SolidaridadPU").createEntityManager();
            } else {
                entity = Persistence.createEntityManagerFactory("ONGD_Persona_Solidaridad_PruebasPU").createEntityManager();
            }
        } catch (Exception ex) {
            resultado = false;
        }
        return resultado;
    }

    /**
     * Método que cierra la conexión con la base de datos.
     */
    public void cerrarBaseDatos() {
        if (entity != null && entity.getEntityManagerFactory().isOpen()) {
            entity.getEntityManagerFactory().close();
        }
    }

    /**
     * Método que registra los controladores de la base de datos.
     */
    public void registrarJPAControladores() {
        hsmJPAControladores.put(Persona.class, new PersonaJpaController(entity));
        hsmJPAControladores.put(Proyecto.class, new ProyectoJpaController(entity));
        hsmJPAControladores.put(Fraccionado.class, new FraccionadoJpaController(entity));
        hsmJPAControladores.put(Cuota.class, new CuotaJpaController(entity));
        hsmJPAControladores.put(Apadrinado.class, new ApadrinadoJpaController(entity));
        hsmJPAControladores.put(PersonaContacto.class, new PersonaContactoJpaController(entity));
        hsmJPAControladores.put(Subvencion.class, new SubvencionJpaController(entity));
        hsmJPAControladores.put(Indice.class, new IndiceJpaController(entity));
        hsmJPAControladores.put(Usuario.class, new UsuarioJpaController(entity));
        hsmJPAControladores.put(Configuracion.class, new ConfiguracionJpaController(entity));
    }

    /**
     * Método que inicia una transaccion con la base de datos.
     */
    public void iniciarTransaccion() {
        entity.getTransaction().begin();
        blnTransaccion = true;
    }

    /**
     * Método que termina una transacción con la base de datos.
     */
    public void terminarTransaccion() {
        entity.getTransaction().commit();
        blnTransaccion = false;
    }

    /**
     * Método que crea un objeto de tipo entidad en la base de datos.
     * @param entidad Entidad a crear
     * @throws PreexistingEntityException
     * @throws Exception 
     */
    public void crearEntidad(Entidad entidad) throws PreexistingEntityException, Exception {
        hsmJPAControladores.get(entidad.getClass()).create(entidad, blnTransaccion);
    }

    /**
     * Edita mediante el controlador correspondiente una instancia de tipo 
     * Entidad.
     * @param entidad Entidad a editar
     * @throws IllegalOrphanException 
     * @throws NonexistentEntityException 
     * @throws Exception 
     */
    public void editarEntidad(Entidad entidad) throws IllegalOrphanException, NonexistentEntityException, Exception {
        hsmJPAControladores.get(entidad.getClass()).edit(entidad, blnTransaccion);
    }

    /**
     * Eliminia mediante el controlador correspondiente una instancia de 
     * tipo Entidad. 
     * @param clase Tipo que será borrado
     * @param obj Clave del objeto que será borrado
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException 
     */
    public void destroyEntidad(Class clase, Object obj) throws IllegalOrphanException, NonexistentEntityException {
        hsmJPAControladores.get(clase).destroy(clase, obj, blnTransaccion);
    }

    /**
     * Obtiene una instancia de tipo Entidad.    
     * @param clase Tipo de objeto a obtener
     * @param obj Clave del objeto
     * @return entidad
     */
    public Entidad obtenerEntidad(Class clase, Object obj) {
        return hsmJPAControladores.get(clase).findEntidad(clase, obj);
    }

    /**
     * Obtiene una lista de entidades.
     * @param clase Class correspondiente a las entidades 
     * @return lista
     */
    public List<? extends Entidad> obtenerEntidades(Class clase) {
        return hsmJPAControladores.get(clase).findEntities(clase, entity);
    }

    /**
     * Obtiene el número de registros de una determinada entidad.
     * @param clase Class correspondiente a la entidad
     * @return numEntidades
     */
    public int obtenerNumEntidades(Class clase) {
        return hsmJPAControladores.get(clase).getEntidadCount(clase, entity);
    }

    /**
     * Nos indica si es necesario iniciar la transacción o no.
     * @return blnTransaccion
     */
    public boolean isBlnTransaccion() {
        return blnTransaccion;
    }

    /**
     * Método que devuelve el entity manager de la clase.
     * @return entity
     * @see #setEntity
     */
    public EntityManager getEntity() {
        return entity;
    }

    /**
     * Método que devuelve el hashmap que va a contener los controladores.
     * @return hasmJPAControladores
     * @see #setHsmJPAControladores
     */
    public HashMap<Class, AJPAControlador> getHsmJPAControladores() {
        return hsmJPAControladores;
    }

    /**
     * Método que asigna un nuevo valor que indica si se debe iniciar la transaccion.
     * @param blnTransaccion Nuevo valor de la variable
     */
    public void setBlnTransaccion(boolean blnTransaccion) {
        this.blnTransaccion = blnTransaccion;
    }

    /**
     * Método que asigna un nuevo valor al entity manager.
     * @param entity Nuevo valor de la variable
     * @see #getEntity
     */
    public void setEntity(EntityManager entity) {
        this.entity = entity;
    }

    /**
     * Método que asigna un nuevo hashmap que va a contener los controladores.
     * @param hsmJPAControladores Nuevo valor de la variable
     * @see #getHsmJPAControladores
     */
    public void setHsmJPAControladores(HashMap<Class, AJPAControlador> hsmJPAControladores) {
        this.hsmJPAControladores = hsmJPAControladores;
    }
}
